home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / NR3.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-07  |  30.7 KB  |  1,152 lines

  1. /* net/rom level 3 low level processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5. /* Mods by PA0GRI and WG7J */
  6.  
  7. #include "global.h"
  8. #ifdef NETROM
  9. #include "ctype.h"
  10. #include "commands.h"
  11. #include "mbuf.h"
  12. #include "pktdrvr.h"
  13. #include "arp.h"
  14. #include "netrom.h"
  15. #include "trace.h"
  16.  
  17. #if !defined(_lint)
  18. static char rcsid[] OPTIONAL = "$Id: nr3.c,v 1.21 1997/09/07 21:18:28 root Exp root $";
  19. #endif
  20.  
  21. /* IF the following is defined,
  22.  * when we receive a nodes broadcast of a new neighbour,
  23.  * we will immediately respond with a nodes broadcast on that interface
  24.  * This speeds up route discovery at bootup etc..
  25.  * 920422 - WG7J
  26.  */
  27. #define NR_BC_RESPOND 1
  28.  
  29. static int accept_bc (char *addr, struct iface * ifp);
  30. struct nr_bind *find_best (struct nr_bind * list, unsigned obso);
  31. static struct nr_bind *find_binding (struct nr_bind * list, struct nrnbr_tab * neighbor);
  32. struct nrnbr_tab *find_nrnbr (char *, struct iface *);
  33. void nrresetlinks (struct nrroute_tab * rp);    /* s/b in a header file */
  34. static struct nrnf_tab *find_nrnf (char *, struct iface *);
  35. static struct nr_bind *find_worst (struct nr_bind * list);
  36. extern void doobsotick (void);
  37.  
  38. static struct raw_nr *Raw_nr;
  39. static int nr_aliasck (char *alias);
  40.  
  41. struct nrnbr_tab *Nrnbr_tab[NRNUMCHAINS];
  42. struct nrroute_tab *Nrroute_tab[NRNUMCHAINS];
  43. struct nrnf_tab *Nrnf_tab[NRNUMCHAINS];
  44. unsigned Nr_nfmode = NRNF_NOFILTER;
  45. unsigned short Nr_ttl = 10;
  46. static unsigned Obso_init = 6;    /* The obsolescence count initializer */
  47. static unsigned Obso_minbc = 5;    /* The threshhold at which routes becoming obsolete are not broadcast */
  48.  
  49. /* The maximum number of routes maintained for a destination. */
  50. /* If the list fills up, only the highest quality routes are  */
  51. /* kept.  This limiting is done to avoid possible over-use of */
  52. /* memory for routing tables in closely spaced net/rom networks. */
  53. static unsigned Nr_maxroutes = 5;
  54.  
  55. unsigned Nr_autofloor = 10;
  56. int Nr_derate = 1;        /* Allow automatic derating of routes */
  57. int Nr_promisc = 0;        /* behave promisuously with nr bcasts or not? */
  58. struct iface *Nr_iface;
  59. static const char temproute[] = "##temp";
  60.  
  61. extern char Nralias[ALEN + 1];
  62.  
  63.  
  64. /* send a NET/ROM layer 3 datagram */
  65. void
  66. nr3output (dest, data)
  67. char *dest;
  68. struct mbuf *data;
  69. {
  70. struct nr3hdr n3hdr;
  71. struct mbuf *n3b;
  72.  
  73.     memcpy (n3hdr.dest, dest, AXALEN);    /* copy destination field */
  74.     n3hdr.ttl = Nr_ttl;    /* time to live from initializer parm */
  75.  
  76.     if ((n3b = htonnr3 (&n3hdr)) == NULLBUF) {
  77.         free_p (data);
  78.         return;
  79.     }
  80.     append (&n3b, data);
  81.     /* The null interface indicates that the packet needs to have */
  82.     /* an appropriate source address inserted by nr_route */
  83.     nr_route (n3b, NULLAX25);
  84. }
  85.  
  86.  
  87. /* send IP datagrams across a net/rom network connection */
  88. int
  89. nr_send (bp, iface, gateway, prec, del, tput, rel)
  90. struct mbuf *bp;
  91. struct iface *iface;
  92. uint32 gateway;
  93. int prec OPTIONAL;
  94. int del OPTIONAL;
  95. int tput OPTIONAL;
  96. int rel OPTIONAL;
  97. {
  98. struct arp_tab *arp;
  99.  
  100.     dump (iface, IF_TRACE_OUT, CL_NETROM, bp);
  101.  
  102.     if ((arp = arp_lookup (ARP_NETROM, gateway, iface)) == NULLARP) {
  103.         free_p (bp);    /* drop the packet if no route */
  104.         return -1;
  105.     }
  106.     iface->rawsndcnt++;
  107.     Nr_iface->ipsndcnt++;
  108.     iface->lastsent = Nr_iface->lastsent = secclock ();
  109.  
  110.     nr_sendraw (arp->hw_addr, NRPROTO_IP, NRPROTO_IP, bp);
  111.     return 0;
  112. }
  113.  
  114.  
  115. /* Send arbitrary protocol data on top of a NET/ROM connection */
  116. void
  117. nr_sendraw (dest, family, proto, data)
  118. char *dest;
  119. unsigned family;
  120. unsigned proto;
  121. struct mbuf *data;
  122. {
  123. struct mbuf *pbp;
  124. struct nr4hdr n4hdr;
  125.  
  126.     /* Create a "network extension" transport header */
  127.     n4hdr.opcode = NR4OPPID;
  128.     n4hdr.u.pid.family = uchar(family);
  129.     n4hdr.u.pid.proto = uchar(proto);
  130.  
  131.     if ((pbp = htonnr4 (&n4hdr)) == NULLBUF) {
  132.         free_p (data);
  133.         return;
  134.     }
  135.     append (&pbp, data);    /* Append the data to that */
  136.     nr3output (dest, pbp);    /* and pass off to level 3 code */
  137. }
  138.  
  139.  
  140. /* Arrange for receipt of raw NET/ROM datagrams */
  141. struct raw_nr *
  142. raw_nr (protocol)
  143. char protocol;
  144. {
  145. register struct raw_nr *rp;
  146.  
  147.     rp = (struct raw_nr *) callocw (1, sizeof (struct raw_nr));
  148.  
  149.     rp->protocol = protocol;
  150.     rp->next = Raw_nr;
  151.     if (rp->next != NULLRNR)
  152.         rp->next->prev = rp;
  153.     Raw_nr = rp;
  154.     return rp;
  155. }
  156.  
  157.  
  158. /* Free a raw NET/ROM descriptor */
  159. void
  160. del_rnr (rpp)
  161. struct raw_nr *rpp;
  162. {
  163. register struct raw_nr *rp;
  164.  
  165.     /* Do sanity check on arg */
  166.     for (rp = Raw_nr; rp != NULLRNR; rp = rp->next)
  167.         if (rp == rpp)
  168.             break;
  169.     if (rp == NULLRNR)
  170.         return;        /* Doesn't exist */
  171.  
  172.     /* Unlink */
  173.     if (rp->prev != NULLRNR)
  174.         rp->prev->next = rp->next;
  175.     else
  176.         Raw_nr = rp->next;
  177.     if (rp->next != NULLRNR)
  178.         rp->next->prev = rp->prev;
  179.     /* Free resources */
  180.     free_q (&rp->rcvq);
  181.     free ((char *) rp);
  182. }
  183.  
  184.  
  185. /* Route net/rom network layer packets.
  186.  */
  187. void
  188. nr_route (bp, iaxp)
  189. struct mbuf *bp;        /* network packet */
  190. struct ax25_cb *iaxp;        /* incoming ax25 control block */
  191. {
  192. struct nr3hdr n3hdr;
  193. struct nr4hdr n4hdr;
  194. struct ax25_cb *axp;
  195. struct mbuf *hbp, *pbp;
  196. struct raw_nr *rnr;
  197. register struct nrnbr_tab *np;
  198. register struct nrroute_tab *rp;
  199. register struct nr_bind *bindp;
  200. struct iface *iface;
  201.  
  202.     if (ntohnr3 (&n3hdr, &bp) == -1) {
  203.         free_p (bp);
  204.         return;
  205.     }
  206.     /* If this isn't an internally generated network packet,
  207.      * give the router a chance to record a route back to the
  208.      * sender, in case they aren't in the local node's routing
  209.      * table yet.
  210.      */
  211.     if (iaxp != NULLAX25 /* && ax_lookup(iaxp->remote,iaxp->iface) != NULLAXR */ ) {
  212.  
  213.         /* find the interface number */
  214.         if (!(iaxp->iface->flags & IS_NR_IFACE)) {    /* Not a net/rom interface! */
  215.             free_p (bp);
  216.             return;
  217.         }
  218.         /* Add (possibly) a zero-quality recorded route via */
  219.         /* the neighbor from which this packet was received */
  220.         /* Note that this doesn't work with digipeated neighbors. */
  221.  
  222.         (void) nr_routeadd (temproute, n3hdr.source, iaxp->iface, 0, iaxp->remote, 0, 1);
  223.     }
  224.     /* Add some statictics gathering - WG7J */
  225.     if (iaxp == NULLAX25) {    /* a locally generated, ie outgoing, packet */
  226.         Nr_iface->rawsndcnt++;
  227.         Nr_iface->lastsent = secclock ();
  228.     } else {        /* incoming packet */
  229.         Nr_iface->rawrecvcnt++;
  230.         Nr_iface->lastrecv = secclock ();
  231.     }
  232.  
  233.     /* A packet from me, to me, can only be one thing:
  234.      * a horrible routing loop.  This will probably result
  235.      * from a bad manual ARP entry, but we should fix these
  236.      * obscure errors as we find them.
  237.      */
  238.     if (addreq (Nr_iface->hwaddr, n3hdr.dest)) {
  239.         /* Toss if from me, or if we can't read the header */
  240.         if (iaxp == NULLAX25 || ntohnr4 (&n4hdr, &bp) == -1)
  241.             free_p (bp);
  242.         else if ((n4hdr.opcode & NR4OPCODE) == NR4OPPID) {
  243.             for (rnr = Raw_nr; rnr != NULLRNR; rnr = rnr->next) {
  244.                 if ((unsigned char) rnr->protocol != n4hdr.u.pid.family ||
  245.                     (unsigned char) rnr->protocol != n4hdr.u.pid.proto)
  246.                     continue;
  247.                 /* Duplicate the data portion, and put the
  248.                  * level 3 header back on
  249.                  */
  250.                 (void) dup_p (&pbp, bp, 0, len_p (bp));
  251.                 if (pbp != NULLBUF &&
  252.                     (hbp = htonnr3 (&n3hdr)) != NULLBUF) {
  253.                     append (&hbp, pbp);
  254.                     enqueue (&rnr->rcvq, hbp);
  255.                 } else {
  256.                     free_p (pbp);
  257.                     free_p (hbp);
  258.                 }
  259.             }
  260.             /* IP does not use a NET/ROM level 3 socket */
  261.             if (n4hdr.u.pid.family == NRPROTO_IP
  262.                 && n4hdr.u.pid.proto == NRPROTO_IP)
  263.                 (void) ip_route (iaxp->iface, bp, 0);
  264.             else    /* we don't do this proto */
  265.                 free_p (bp);
  266.         } else {
  267.             /* Must be net/rom transport: */
  268.             nr4input (&n4hdr, bp);
  269.         }
  270.         return;
  271.     }
  272.     if ((rp = find_nrroute (n3hdr.dest)) == NULLNRRTAB) {
  273.         /* no route, drop the packet */
  274.         free_p (bp);
  275.         return;
  276.     }
  277.     if ((bindp = find_best (rp->routes, 1)) == NULLNRBIND) {
  278.         /* This shouldn't happen yet, but might if we add */
  279.         /* dead route detection */
  280.         free_p (bp);
  281.         return;
  282.     }
  283.     np = bindp->via;
  284.     iface = np->iface;
  285.  
  286.     /*Update the last-used timestamp - WG7J */
  287.     np->lastsent = secclock ();
  288.  
  289.  
  290.     /* Now check to see if iaxp is null.  That is */
  291.     /* a signal that the packet originates here, */
  292.     /* so we need to insert the callsign of the appropriate  */
  293.     /* interface */
  294.     if (iaxp == NULLAX25)
  295.         memcpy (n3hdr.source, Nr_iface->hwaddr, AXALEN);
  296.  
  297.     /* Make sure there is a connection to the neighbor */
  298.     /* Make sure we use the netrom-interface call for this connection!
  299.      * 11/20/91 WG7J/PA3DIS
  300.      */
  301.     if ((axp = find_ax25 (Nr_iface->hwaddr, np->call, iface)) == NULLAX25 ||
  302.         (axp->state != LAPB_CONNECTED && axp->state != LAPB_RECOVERY)) {
  303.         /* Open a new connection or reinitialize old one */
  304.         /* hwaddr has been advanced to point to neighbor + digis */
  305.         axp = open_ax25 (iface, Nr_iface->hwaddr, np->call, AX_ACTIVE, Axwindow, s_arcall, s_atcall, s_ascall, -1);
  306.         if (axp == NULLAX25) {
  307.             free_p (bp);
  308.             return;
  309.         }
  310.     }
  311.     if (--n3hdr.ttl == 0) {    /* the packet's time to live is over! */
  312.         free_p (bp);
  313.         return;
  314.     }
  315.     /* now format network header */
  316.     if ((pbp = htonnr3 (&n3hdr)) == NULLBUF) {
  317.         free_p (bp);
  318.         return;
  319.     }
  320.     append (&pbp, bp);    /* append data to header */
  321.  
  322.     /* put AX.25 PID on front */
  323.     if ((bp = pushdown (pbp, 1)) == NULLBUF) {
  324.         free_p (pbp);
  325.         return;
  326.     }
  327.     bp->data[0] = PID_NETROM;
  328.  
  329.     if ((pbp = segmenter (bp, axp->paclen, axp)) == NULLBUF) {
  330.         free_p (bp);
  331.         return;
  332.     }
  333.     (void) send_ax25 (axp, pbp, -1);    /* pass it off to ax25 code */
  334. }
  335.  
  336.  
  337. /* Perform a nodes broadcast on interface # ifno in the net/rom
  338.  * interface table.
  339.  */
  340. /* This uses Nralias as the alias instead of Nriface.alias as before - WG7J */
  341. void
  342. nr_bcnodes (ifp)
  343. struct iface *ifp;
  344. {
  345. struct mbuf *hbp, *dbp, *savehdr;
  346. struct nrroute_tab *rp;
  347. struct nrnbr_tab *np;
  348. struct nr_bind *bp;
  349. struct nr3dest nrdest;
  350. int i, didsend = 0, numdest = 0;
  351.  
  352.     /* prepare the header */
  353.     if ((hbp = alloc_mbuf (NR3NODEHL)) == NULLBUF)
  354.         return;
  355.  
  356.     hbp->cnt = NR3NODEHL;
  357.  
  358.     *hbp->data = NR3NODESIG;
  359.  
  360.     memcpy (hbp->data + 1, Nralias, ALEN);
  361.  
  362.     /* Some people don't want to advertise any routes; they
  363.      * just want to be a terminal node.  In that case we just
  364.      * want to send our call and alias and be done with it.
  365.      */
  366.  
  367.     if (!(ifp->flags & NR_VERBOSE)) {
  368.         /*changed to use the Netrom interface call on all broadcasts,
  369.              *INDEPENDENT from the actual interface call!
  370.              *11/20/91 WG7J/PA3DIS
  371.              */
  372.         (void) (*ifp->output) (ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr, PID_NETROM, hbp);    /* send it */
  373.         return;
  374.     }
  375.     /* make a copy of the header in case we need to send more than */
  376.     /* one packet */
  377.     savehdr = copy_p (hbp, NR3NODEHL);
  378.  
  379.     /* now scan through the routing table, finding the best routes */
  380.     /* and their neighbors.  create destination subpackets and append */
  381.     /* them to the header */
  382.     for (i = 0; i < NRNUMCHAINS; i++) {
  383.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
  384.             /* look for best, non-obsolescent route */
  385.             if ((bp = find_best (rp->routes, 0)) == NULLNRBIND)
  386.                 continue;    /* no non-obsolescent routes found */
  387.  
  388.             if (bp->quality == 0)    /* this is a loopback route */
  389.                 continue;    /* we never broadcast these */
  390.  
  391.             if (bp->quality < Nr_autofloor)    /* below threshhold route */
  392.                 continue;    /* so don't broadcast it */
  393.  
  394.             if (nr_aliasck (rp->alias))    /* corrupted alias entry? */
  395.                 continue;    /* don't rebroadcast it */
  396.             /* safety measure! */
  397.             np = bp->via;
  398.             /* insert best neighbor */
  399.             if (np && np->call)
  400.                 memcpy (nrdest.neighbor, np->call, AXALEN);
  401.             else
  402.                 memcpy (nrdest.neighbor, rp->call, AXALEN);
  403.             /* insert destination from route table */
  404.             memcpy (nrdest.dest, rp->call, AXALEN);
  405.             /* insert alias from route table */
  406.             strcpy (nrdest.alias, rp->alias);
  407.             /* insert quality from binding */
  408.             nrdest.quality = bp->quality;
  409.             /* create a network format destination subpacket */
  410.             if ((dbp = htonnrdest (&nrdest)) == NULLBUF) {
  411.                 free_p (hbp);    /* drop the whole idea ... */
  412.                 free_p (savehdr);
  413.                 return;
  414.             }
  415.             /* we now have a partially filled packet */
  416.             didsend = 0;
  417.             append (&hbp, dbp);    /* append to header and others */
  418.             /* see if we have appended as many destinations
  419.              * as we can fit into a single broadcast.  If we
  420.              * have, go ahead and send them out.
  421.              */
  422.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  423.                 /* indicate that we did broadcast */
  424.                 didsend = 1;
  425.                 /* reset the destination counter */
  426.                 numdest = 0;
  427.                 (void) (*ifp->output) (ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr, PID_NETROM, hbp);    /* send it */
  428.                 /* new header */
  429.                 hbp = copy_p (savehdr, NR3NODEHL);
  430.             }
  431.         }
  432.     }
  433.  
  434.     /* If we have a partly filled packet left over, or we never */
  435.     /* sent one at all, we broadcast: */
  436.  
  437.     if (!didsend || numdest > 0)
  438.         (void) (*ifp->output) (ifp, Ax25multi[NODESCALL], Nr_iface->hwaddr, PID_NETROM, hbp);
  439.     else {
  440.         if (numdest == 0)    /* free the header copies */
  441.             free_p (hbp);
  442.     }
  443.  
  444.     free_p (savehdr);
  445. }
  446.  
  447.  
  448. /* Perform a nodes broadcast poll on interface ifp
  449.  * in the net/rom interface table. - WG7J
  450.  */
  451. void
  452. nr_bcpoll (ifp)
  453. struct iface *ifp;
  454. {
  455. struct mbuf *hbp;
  456.  
  457.     /* prepare the header */
  458.     if ((hbp = alloc_mbuf (NR3NODEHL)) == NULLBUF)
  459.         return;
  460.     hbp->cnt = NR3NODEHL;
  461.     *hbp->data = NR3POLLSIG;
  462.     memcpy (hbp->data + 1, Nralias, ALEN);
  463.  
  464.     /* send it out */
  465.     (void) (*ifp->output) (ifp, Ax25multi[1], Nr_iface->hwaddr, PID_NETROM, hbp);
  466.     return;
  467. }
  468.  
  469.  
  470. extern struct timer Nodetimer, Obsotimer;
  471.  
  472. /* attach the net/rom interface.  no parms for now. */
  473. int
  474. nr_attach (argc, argv, p)
  475. int argc OPTIONAL;
  476. char *argv[] OPTIONAL;
  477. void *p OPTIONAL;
  478. {
  479.     if (Nr_iface != (struct iface *) 0) {
  480.         tputs ("netrom interface already attached\n");
  481.         return -1;
  482.     }
  483.     Nr_iface = (struct iface *) callocw (1, sizeof (struct iface));
  484.  
  485.     Nr_iface->addr = Ip_addr;
  486.     Nr_iface->iface_metric = 1;
  487.  
  488.     /* The strdup is needed to keep the detach routine happy (it'll
  489.      * free the allocated memory)
  490.      */
  491.     Nr_iface->name = strdup ("netrom");
  492.     if (Nr_iface->hwaddr == NULLCHAR) {
  493.         Nr_iface->hwaddr = mallocw (AXALEN);
  494.         memcpy (Nr_iface->hwaddr, Mycall, AXALEN);
  495.     }
  496.     Nr_iface->mtu = NR4MAXINFO;
  497.     (void) setencap (Nr_iface, "NETROM");
  498.     Nr_iface->next = Ifaces;
  499.     Ifaces = Nr_iface;
  500.     memcpy (Nr4user, Mycall, AXALEN);
  501.  
  502.     /* Added some default settings for node-broadcast interval and
  503.      * obsolescence timers. 11/21/91 WG7J/PA3DIS
  504.      */
  505.     stop_timer (&Nodetimer);
  506.     Nodetimer.func = (void (*)(void *)) donodetick;    /* what to call on timeout */
  507.     Nodetimer.arg = NULLCHAR;    /* dummy value */
  508.     set_timer (&Nodetimer, 1800000L);    /* 'standard netrom' 30 minutes*/
  509.     start_detached_timer (&Nodetimer);    /* and fire it up */
  510.  
  511.     stop_timer (&Obsotimer);
  512.     Obsotimer.func = (void (*)(void *)) doobsotick;    /* what to call on timeout */
  513.     Obsotimer.arg = NULLCHAR;    /* dummy value */
  514.     set_timer (&Obsotimer, 2100000L);    /* 35 minutes */
  515.     start_detached_timer (&Obsotimer);    /* and fire it up */
  516.  
  517.     return 0;
  518. }
  519.  
  520.  
  521. /* This function checks an ax.25 address and interface number against
  522.  * the filter table and mode, and returns -1 if the address is to be accepted
  523.  * verbatim, the quality if filtered in or 0 if it is to be filtered out.
  524.  */
  525. static int
  526. accept_bc (addr, ifp)
  527. char *addr;
  528. struct iface *ifp;
  529. {
  530. struct nrnf_tab *fp;
  531.  
  532.     if (Nr_nfmode == NRNF_NOFILTER)    /* no filtering in effect */
  533.         return -1;
  534.  
  535.     fp = find_nrnf (addr, ifp);    /* look it up */
  536.  
  537.     if (fp != NULLNRNFTAB && Nr_nfmode == NRNF_ACCEPT)
  538.         return ((int)fp->quality);
  539.  
  540.     if (fp == NULLNRNFTAB && Nr_nfmode == NRNF_REJECT)
  541.         return -1;
  542.  
  543.     if (Nr_promisc)
  544.         return -1;    /* Come up and see me sometime..... */
  545.     else
  546.         return 0;    /* My mummy said not to listen to strangers! */
  547. }
  548.  
  549.  
  550. /* receive and process node broadcasts. */
  551. void
  552. nr_nodercv (iface, source, bp)
  553. struct iface *iface;
  554. char *source;
  555. struct mbuf *bp;
  556. {
  557. char bcalias[AXALEN];
  558. struct nr3dest ds;
  559. int qual, poll;
  560. unsigned char c;
  561. struct mbuf **bpp = &bp;
  562.  
  563.     /* First, see if this is even a net/rom interface: */
  564.     if (!(iface->flags & IS_NR_IFACE)) {
  565.         free_p (bp);
  566.         return;
  567.     }
  568.     if ((qual = accept_bc (source, iface)) == 0) {    /* check against filter */
  569.         free_p (bp);    /* and get quality */
  570.         return;
  571.     }
  572.     c = uchar(PULLCHAR (bpp));
  573.     /* is this a route update poll from a neigbour ? - WG7J */
  574.     poll = 0;
  575.     if (c == NR3POLLSIG) {
  576.         poll = 1;
  577.         nr_bcnodes (iface);    /* broadcast our routes */
  578.     } else        /* See if it has a routing broadcast signature: */
  579.     if (c != NR3NODESIG) {
  580.         free_p (bp);
  581.         return;
  582.     }
  583.     /* now try to get the alias */
  584.     if (pullup (&bp, (unsigned char *) bcalias, ALEN) < ALEN) {
  585.         free_p (bp);
  586.         return;
  587.     }
  588.     /* now check that the alias field is not corrupted - saftey measure! */
  589.     if (nr_aliasck (bcalias)) {
  590.         free_p (bp);
  591.         return;
  592.     }
  593.     bcalias[ALEN] = '\0';    /* null terminate */
  594.  
  595. #ifdef NR_BC_RESPOND
  596.     /* If we were polled, we've already sent the routes list - WG7J */
  597.     if (!poll && (find_nrnbr (source, iface) == NULLNTAB))    /* a new node ! */
  598.         nr_bcnodes (iface);
  599. #endif
  600.  
  601.     /* enter the neighbor into our routing table */
  602.     if (qual == -1)
  603.         qual = iface->quality;    /* use default quality */
  604.  
  605.     if (nr_routeadd (bcalias, source, iface, (unsigned) qual, source, 0, 0) == -1) {
  606.         free_p (bp);
  607.         return;
  608.     }
  609.     /* we've digested the header; now digest the actual */
  610.     /* routing information */
  611.     while (ntohnrdest (&ds, &bp) != -1) {
  612.  
  613.         /* ignore routes to me! */
  614.         if (addreq (Nr_iface->hwaddr, ds.dest))
  615.             continue;
  616.  
  617.         /* ignore routes with corrupted aliases - safety measure */
  618.         if (nr_aliasck (ds.alias))
  619.             continue;
  620.  
  621.         /* ignore loopback paths to ourselves */
  622.         if (addreq (Nr_iface->hwaddr, ds.neighbor))
  623.             continue;
  624.         else
  625.             ds.quality = ((ds.quality * (int16) qual + 128) / 256) & 0xff;
  626.  
  627.         /* ignore routes below the minimum quality threshhold */
  628.         if (ds.quality < Nr_autofloor)
  629.             continue;
  630.  
  631.         if (nr_routeadd (ds.alias, ds.dest, iface, ds.quality, source, 0, 0)
  632.             == -1)
  633.             break;
  634.     }
  635.     free_p (bp);        /* This will free the mbuf if anything fails above */
  636. }
  637.  
  638.  
  639. /* The following are utilities for manipulating the routing table */
  640.  
  641. /* hash function for callsigns.  Look familiar? */
  642. int16
  643. nrhash (s)
  644. char *s;
  645. {
  646. register char x;
  647. register int i;
  648.  
  649.     x = 0;
  650.     for (i = ALEN; i != 0; i--)
  651.         x ^= (char)(*s++ & 0xfe);
  652.     x ^= *s & SSID;
  653.     return (int16) (uchar (x) % NRNUMCHAINS);
  654. }
  655.  
  656.  
  657. /* Find a neighbor table entry.  Neighbors are determined by
  658.  * their callsign and the interface number.  This takes care
  659.  * of the case where the same switch or hosts uses the same
  660.  * callsign on two different channels.  This isn't done by
  661.  * net/rom, but it might be done by stations running *our*
  662.  * software.
  663.  */
  664. struct nrnbr_tab *
  665. find_nrnbr (addr, ifp)
  666. register char *addr;
  667. struct iface *ifp;
  668. {
  669. int16 hashval;
  670. register struct nrnbr_tab *np;
  671.  
  672.     /* Find appropriate hash chain */
  673.     hashval = nrhash (addr);
  674.  
  675.     /* search hash chain */
  676.     for (np = Nrnbr_tab[hashval]; np != NULLNTAB; np = np->next) {
  677.         /* convert first in  list to ax25 address format */
  678.         if (addreq (np->call, addr) && np->iface == ifp) {
  679.             return np;
  680.         }
  681.     }
  682.     return NULLNTAB;
  683. }
  684.  
  685.  
  686. /* Try to find the AX.25 address of a node with the given call or alias.
  687.  * Return a pointer to the route if found, otherwize NULLNRRTAB.
  688.  * alias should be a six character, blank-padded, upper-case string.
  689.  * call should be a upper-case string.
  690.  * 12-21-91, WG7J
  691.  */
  692.  
  693. struct nrroute_tab *
  694. find_nrboth (alias, call)
  695. char *alias;
  696. char *call;
  697. {
  698. int i;
  699. register struct nrroute_tab *rp;
  700. char tmp[AXBUF];
  701.  
  702.     /* Since the route entries are hashed by ax.25 address, we'll */
  703.     /* have to search all the chains */
  704.  
  705.     for (i = 0; i < NRNUMCHAINS; i++)
  706.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
  707.             if ((strncmp (alias, rp->alias, 6) == 0) ||
  708.                 (strcmp (call, pax25 (tmp, rp->call)) == 0))
  709.                 return rp;
  710.  
  711.     /* If we get to here, we're out of luck */
  712.     return NULLNRRTAB;
  713. }
  714.  
  715.  
  716. /* Find a route table entry */
  717. struct nrroute_tab *
  718. find_nrroute (addr)
  719. register char *addr;
  720. {
  721. int16 hashval;
  722. register struct nrroute_tab *rp;
  723.  
  724.     /* Find appropriate hash chain */
  725.     hashval = nrhash (addr);
  726.  
  727.     if (hashval >= NRNUMCHAINS)    /* should NEVER happen */
  728.         return NULLNRRTAB;
  729.  
  730.     /* search hash chain */
  731.     for (rp = Nrroute_tab[hashval]; rp != NULLNRRTAB; rp = rp->next) {
  732.         if (addreq (rp->call, addr)) {
  733.             return rp;
  734.         }
  735.     }
  736.     return NULLNRRTAB;
  737. }
  738.  
  739.  
  740. #if 0
  741. /* Try to find the AX.25 address of a node with the given alias.  Return */
  742. /* a pointer to the AX.25 address if found, otherwise NULLCHAR.  The alias */
  743. /* should be a six character, blank-padded, upper-case string. */
  744.  
  745. static char *
  746. find_nralias (alias)
  747. char *alias;
  748. {
  749. int i;
  750. register struct nrroute_tab *rp;
  751.  
  752.     /* Since the route entries are hashed by ax.25 address, we'll */
  753.     /* have to search all the chains */
  754.  
  755.     for (i = 0; i < NRNUMCHAINS; i++)
  756.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next)
  757.             if (strncmp (alias, rp->alias, 6) == 0)
  758.                 return rp->call;
  759.  
  760.     /* If we get to here, we're out of luck */
  761.  
  762.     return NULLCHAR;
  763. }
  764. #endif
  765.  
  766.  
  767. /* Find a binding in a list by its neighbor structure's address */
  768. static struct nr_bind *
  769. find_binding (list, neighbor)
  770. struct nr_bind *list;
  771. register struct nrnbr_tab *neighbor;
  772. {
  773. register struct nr_bind *bp;
  774.  
  775.     for (bp = list; bp != NULLNRBIND; bp = bp->next)
  776.         if (bp->via == neighbor)
  777.             return bp;
  778.  
  779.     return NULLNRBIND;
  780. }
  781.  
  782.  
  783. /* Find the worst quality non-permanent binding in a list */
  784. static
  785. struct nr_bind *
  786. find_worst (list)
  787. struct nr_bind *list;
  788. {
  789. register struct nr_bind *bp;
  790. struct nr_bind *worst = NULLNRBIND;
  791. unsigned minqual = 1000;/* infinity */
  792.  
  793.     for (bp = list; bp != NULLNRBIND; bp = bp->next)
  794.         if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  795.             worst = bp;
  796.             minqual = bp->quality;
  797.         }
  798.     return worst;
  799. }
  800.  
  801.  
  802. /* Find the best binding of any sort in a list.  If obso is 1,
  803.  * include entries below the obsolescence threshhold in the
  804.  * search (used when this is called for routing broadcasts).
  805.  * If it is 0, routes below the threshhold are treated as
  806.  * though they don't exist.
  807.  */
  808. struct nr_bind *
  809. find_best (list, obso)
  810. struct nr_bind *list;
  811. unsigned obso;
  812. {
  813. register struct nr_bind *bp;
  814. struct nr_bind *best = NULLNRBIND;
  815. int maxqual = -1;    /* negative infinity */
  816.  
  817.     for (bp = list; bp != NULLNRBIND; bp = bp->next)
  818.         if ((int) bp->quality > maxqual)
  819.             if (obso || bp->obsocnt >= Obso_minbc) {
  820.                 best = bp;
  821.                 maxqual = (int) bp->quality;
  822.             }
  823.     return best;
  824. }
  825.  
  826.  
  827. /* Add a route to the net/rom routing table */
  828. int
  829. nr_routeadd (alias, dest, ifp, quality, neighbor, permanent, record)
  830. const char *alias;        /* net/rom node alias, blank-padded and null-terminated */
  831. char *dest;            /* destination node callsign */
  832. struct iface *ifp;
  833. unsigned quality;        /* route quality */
  834. char *neighbor;            /* neighbor node + 2 digis (max) in arp format */
  835. unsigned permanent;        /* 1 if route is permanent (hand-entered) */
  836. unsigned record;        /* 1 if route is a "record route" */
  837. {
  838. struct nrroute_tab *rp;
  839. struct nr_bind *bp;
  840. struct nrnbr_tab *np;
  841. int16 rhash, nhash;
  842.  
  843.     /* See if a routing table entry exists for this destination */
  844.     if ((rp = find_nrroute (dest)) == NULLNRRTAB) {
  845.         rp = (struct nrroute_tab *) callocw (1, sizeof (struct nrroute_tab));
  846.  
  847.         /* create a new route table entry */
  848.         strncpy (rp->alias, alias, 6);
  849.         memcpy (rp->call, dest, AXALEN);
  850.         rhash = nrhash (dest);
  851.         rp->next = Nrroute_tab[rhash];
  852.         if (rp->next != NULLNRRTAB)
  853.             rp->next->prev = rp;
  854.         Nrroute_tab[rhash] = rp;    /* link at head of hash chain */
  855.     } else if (permanent || !strncmp (rp->alias, temproute, 6))
  856.         strncpy (rp->alias, alias, 6);    /* update the alias */
  857.  
  858.     /* See if an entry exists for this neighbor */
  859.     if ((np = find_nrnbr (neighbor, ifp)) == NULLNTAB) {
  860.         np = (struct nrnbr_tab *) callocw (1, sizeof (struct nrnbr_tab));
  861.  
  862.         /* create a new neighbor entry */
  863.         memcpy (np->call, neighbor, AXALEN);
  864.         np->iface = ifp;
  865.         nhash = nrhash (neighbor);
  866.         np->next = Nrnbr_tab[nhash];
  867.         if (np->next != NULLNTAB)
  868.             np->next->prev = np;
  869.         Nrnbr_tab[nhash] = np;
  870.     } else if (permanent)     /* force this path to the neighbor */
  871.         memcpy (np->call, neighbor, AXALEN);
  872.  
  873.     /* See if there is a binding between the dest and neighbor */
  874.     if ((bp = find_binding (rp->routes, np)) == NULLNRBIND) {
  875.         bp = (struct nr_bind *) callocw (1, sizeof (struct nr_bind));
  876.  
  877.         /* create a new binding and link it in */
  878.         bp->via = np;    /* goes via this neighbor */
  879.         bp->next = rp->routes;    /* link into binding chain */
  880.         if (bp->next != NULLNRBIND)
  881.             bp->next->prev = bp;
  882.         rp->routes = bp;
  883.         rp->num_routes++;    /* bump route count */
  884.         np->refcnt++;    /* bump neighbor ref count */
  885.         bp->quality = quality;
  886.         bp->obsocnt = Obso_init;    /* use initial value */
  887.         if (permanent)
  888.             bp->flags |= NRB_PERMANENT;
  889.         else if (record)/* notice permanent overrides record! */
  890.             bp->flags |= NRB_RECORDED;
  891.     } else {
  892.         if (permanent) {/* permanent request trumps all */
  893.             bp->quality = quality;
  894.             bp->obsocnt = Obso_init;
  895.             bp->flags |= NRB_PERMANENT;
  896.             bp->flags &= ~NRB_RECORDED;    /* perm is not recorded */
  897.         } else if (!(bp->flags & NRB_PERMANENT)) {    /* not permanent */
  898.             if (record) {    /* came from nr_route */
  899.                 if (bp->flags & NRB_RECORDED) {    /* no mod non-rec bindings */
  900.                     bp->quality = quality;
  901.                     bp->obsocnt = Obso_init;    /* freshen recorded routes */
  902.                 }
  903.             } else {/* came from a routing broadcast */
  904.                 bp->quality = quality;
  905.                 bp->obsocnt = Obso_init;
  906.                 bp->flags &= ~NRB_RECORDED;    /* no longer a recorded route */
  907.             }
  908.         }
  909.     }
  910.  
  911.     /* Now, check to see if we have too many bindings, and drop */
  912.     /* the worst if we do */
  913.     if (rp->num_routes > Nr_maxroutes) {
  914.         /* since find_worst never returns permanent entries, the */
  915.         /* limitation on number of routes is circumvented for    */
  916.         /* permanent routes */
  917.         if ((bp = find_worst (rp->routes)) != NULLNRBIND) {
  918.             (void) nr_routedrop (dest, bp->via->call, bp->via->iface);
  919.         }
  920.     }
  921.     return 0;
  922. }
  923.  
  924.  
  925. /* Reset the netrom links to this neighbour, since the
  926.  * route to it just expired - WG7J
  927.  */
  928. void
  929. nrresetlinks (struct nrroute_tab *rp)
  930. {
  931. int i;
  932. struct nr4cb *cb;
  933.  
  934.     for (i = 0; i < NR4MAXCIRC; i++)
  935.         if ((cb = Nr4circuits[i].ccb) != NULLNR4CB)
  936.             if (!memcmp (cb->remote.node, rp->call, AXALEN))
  937.                 reset_nr4 (cb);
  938. }
  939.  
  940.  
  941. /* Drop a route to dest via neighbor */
  942. int
  943. nr_routedrop (dest, neighbor, ifp)
  944. char *dest, *neighbor;
  945. struct iface *ifp;
  946. {
  947. register struct nrroute_tab *rp;
  948. register struct nrnbr_tab *np;
  949. register struct nr_bind *bp;
  950.  
  951.     if ((rp = find_nrroute (dest)) == NULLNRRTAB)
  952.         return -1;
  953.  
  954.     if ((np = find_nrnbr (neighbor, ifp)) == NULLNTAB)
  955.         return -1;
  956.  
  957.     if ((bp = find_binding (rp->routes, np)) == NULLNRBIND)
  958.         return -1;
  959.  
  960.     /* drop the binding first */
  961.     if (bp->next != NULLNRBIND)
  962.         bp->next->prev = bp->prev;
  963.     if (bp->prev != NULLNRBIND)
  964.         bp->prev->next = bp->next;
  965.     else
  966.         rp->routes = bp->next;
  967.  
  968.     free ((char *) bp);
  969.     rp->num_routes--;    /* decrement the number of bindings */
  970.     np->refcnt--;        /* and the number of neighbor references */
  971.  
  972.     /* now see if we should drop the route table entry */
  973.     if (rp->num_routes == 0) {
  974.         if (rp->next != NULLNRRTAB)
  975.             rp->next->prev = rp->prev;
  976.         if (rp->prev != NULLNRRTAB)
  977.             rp->prev->next = rp->next;
  978.         else
  979.             Nrroute_tab[nrhash (dest)] = rp->next;
  980.         /* No more routes left !
  981.              * We should close/reset any netrom connections
  982.              * still idling for this route ! - WG7J
  983.              */
  984.         nrresetlinks (rp);
  985.  
  986.         free ((char *) rp);
  987.     }
  988.     /* and check to see if this neighbor can be dropped */
  989.     if (np->refcnt == 0) {
  990.         if (np->next != NULLNTAB)
  991.             np->next->prev = np->prev;
  992.         if (np->prev != NULLNTAB)
  993.             np->prev->next = np->next;
  994.         else
  995.             Nrnbr_tab[nrhash (neighbor)] = np->next;
  996.  
  997.         free ((char *) np);
  998.     }
  999.     return 0;
  1000. }
  1001.  
  1002.  
  1003. /* Find an entry in the filter table */
  1004. static struct nrnf_tab *
  1005. find_nrnf (addr, ifp)
  1006. register char *addr;
  1007. struct iface *ifp;
  1008. {
  1009. int16 hashval;
  1010. register struct nrnf_tab *fp;
  1011.  
  1012.     /* Find appropriate hash chain */
  1013.     hashval = nrhash (addr);
  1014.  
  1015.     /* search hash chain */
  1016.     for (fp = Nrnf_tab[hashval]; fp != NULLNRNFTAB; fp = fp->next) {
  1017.         if (addreq (fp->neighbor, addr) && (fp->iface == ifp)) {
  1018.             return fp;
  1019.         }
  1020.     }
  1021.  
  1022.     return NULLNRNFTAB;
  1023. }
  1024.  
  1025.  
  1026. /* Add an entry to the filter table.  Return 0 on success,
  1027.  * -1 on failure
  1028.  */
  1029. int
  1030. nr_nfadd (addr, ifp, qual)
  1031. char *addr;
  1032. struct iface *ifp;
  1033. unsigned qual;
  1034. {
  1035. struct nrnf_tab *fp;
  1036. int16 hashval;
  1037.  
  1038.     if (find_nrnf (addr, ifp) != NULLNRNFTAB)
  1039.         return 0;    /* already there; it's a no-op */
  1040.  
  1041.     fp = (struct nrnf_tab *) callocw (1, sizeof (struct nrnf_tab));
  1042.  
  1043.     hashval = nrhash (addr);
  1044.     memcpy (fp->neighbor, addr, AXALEN);
  1045.     fp->iface = ifp;
  1046.     fp->next = Nrnf_tab[hashval];
  1047.     fp->quality = qual;
  1048.     if (fp->next != NULLNRNFTAB)
  1049.         fp->next->prev = fp;
  1050.     Nrnf_tab[hashval] = fp;
  1051.  
  1052.     return 0;
  1053. }
  1054.  
  1055.  
  1056. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  1057.  * on failure.
  1058.  */
  1059. int
  1060. nr_nfdrop (addr, ifp)
  1061. char *addr;
  1062. struct iface *ifp;
  1063. {
  1064. struct nrnf_tab *fp;
  1065.  
  1066.     if ((fp = find_nrnf (addr, ifp)) == NULLNRNFTAB)
  1067.         return -1;    /* not in the table */
  1068.  
  1069.     if (fp->next != NULLNRNFTAB)
  1070.         fp->next->prev = fp->prev;
  1071.     if (fp->prev != NULLNRNFTAB)
  1072.         fp->prev->next = fp->next;
  1073.     else
  1074.         Nrnf_tab[nrhash (addr)] = fp->next;
  1075.  
  1076.     free ((char *) fp);
  1077.  
  1078.     return 0;
  1079. }
  1080.  
  1081.  
  1082. /*
  1083.  * Validate the alias field is good quality ascii to prevent network corruption
  1084.  */
  1085.  
  1086. static int
  1087. nr_aliasck (alias)
  1088. char *alias;
  1089. {
  1090. int x = ALEN;
  1091. int c;
  1092.  
  1093.     while (x--) {
  1094.         c = *alias++;
  1095.         if (!isprint ((int) c))
  1096.             return 1;
  1097.     }
  1098.     return 0;
  1099. }
  1100.  
  1101.  
  1102. /* called from lapb whenever a link failure implies that a particular ax25
  1103.  * path may not be able to carry netrom traffic too well. Experimental!!!!
  1104.  */
  1105. void 
  1106. nr_derate (axp)
  1107. struct ax25_cb *axp;
  1108. {
  1109. register struct nrnbr_tab *np;
  1110. register struct nrroute_tab *rp;
  1111. register struct nr_bind *bp;
  1112. struct mbuf *buf;
  1113. int i;
  1114. int nr_traffic = 0;    /* assume no netrom traffic on connection */
  1115.  
  1116.     if (!Nr_derate)
  1117.         return;        /* derating function is disabled */
  1118.  
  1119.     /* is this an active netrom interface ? */
  1120.     if (!(axp->iface->flags & IS_NR_IFACE))
  1121.         return;
  1122.  
  1123.     if (axp == NULLAX25)
  1124.         return;        /* abandon ship! */
  1125.  
  1126.     /* If it is valid for netrom traffic, lets see if there is */
  1127.     /* really netrom traffic on the connection to be derated.  */
  1128.     for (buf = axp->txq; buf != NULLBUF; buf = buf->anext)
  1129.         if ((buf->data[0] & 0xff) == PID_NETROM)
  1130.             nr_traffic = 1;    /* aha - netrom traffic! */
  1131.  
  1132.     if (!nr_traffic)
  1133.         return;        /* no sign of being used by netrom just now */
  1134.  
  1135.     /* we now have the appropriate interface entry */
  1136.     for (i = 0; i < NRNUMCHAINS; i++) {
  1137.         for (rp = Nrroute_tab[i]; rp != NULLNRRTAB; rp = rp->next) {
  1138.             for (bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1139.                 np = bp->via;
  1140.                 if (bp->quality >= 1 && np->iface == axp->iface &&
  1141.                     !(bp->flags & NRB_PERMANENT) &&
  1142.                     !memcmp (np->call, axp->remote, ALEN) &&
  1143.                     (np->call[6] & SSID) == (axp->remote[6] & SSID)) {
  1144.                     bp->quality = ((bp->quality * 2) / 3);
  1145.                 }
  1146.             }
  1147.         }
  1148.     }
  1149. }
  1150.  
  1151. #endif /* NETROM */
  1152.